package cn.wsn2018.tools.service;

import cn.wsn2018.tools.common.CommonValue;
import cn.wsn2018.tools.dao.SystemConfigDao;
import cn.wsn2018.tools.dao.UserDao;
import cn.wsn2018.tools.model.RsaObj;
import cn.wsn2018.tools.model.SystemConfig;
import cn.wsn2018.tools.model.User;
import cn.wsn2018.tools.model.VO.UserView;
import cn.wsn2018.tools.util.*;
import cn.wsn2018.tools.util.rsa.Base64Utils;
import cn.wsn2018.tools.util.rsa.RSAUtils;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.catalina.manager.util.SessionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


@Service
public class UserService {

    private static final Logger logger = LoggerFactory.getLogger(UserService.class);
    @Autowired
    private UserDao userDao;

    @Autowired
    private SystemConfigDao systemConfigDao;

    /**
     * 业务层,处理用户登录验证
     * @param username 表单提供用户名
     * @param password 表单提供密码
     * @param isLogined 是否在别处登录
     * @return 登录成功与否的状态(无需返回jsonObject或jsonArray)
     */
    public String dealUserLogin(String username, String password, boolean isLogined, boolean flag,
                                HttpServletRequest request) throws Exception {

        //解密
        //System.out.println("RSA解密前："+password);
        //password = Aes.aesDecrypt(password);
        //用Rsa密钥解密
        try{
            password=new String(RSAUtils.decryptByPrivateKey(Base64Utils.decode(password), RsaObj.getInstance().getPrivateKey()));
            //System.out.println("RSA解密后："+password);
        }catch (BadPaddingException bad){
            return JsonUtil.failedJson(CommonValue.JSON_lOGIN_FAILED+",关闭浏览后重试");
        }


        if(username!=null&&!"".equals(username)&&password!=null&&!"".equals(password)){
            username = Regex.checkReg(username);
            password = Regex.checkReg(password);
            //获取当前用户
            User user = userDao.getUserByName(username);

            if(user==null){
                //用户名无匹配账号，直接返回
                return JsonUtil.failedJson(CommonValue.JSON_lOGIN_FAILED);
            }

            //state:0-已经注销 1-休眠  2-激活
            if(user.getState()==CommonValue.STATE_DEL){
               //已经注销的账号，直接失败
                return JsonUtil.failedJson(CommonValue.JSON_lOGIN_FAILED);
            }else if(user.getState()==CommonValue.STATE_SLEEP){
                //账号休眠，需要管理员激活
                return JsonUtil.failedJson(CommonValue.JSON_SLEEP_ACCOUNT_lOGIN_FAILED);
            }

            //锁定判断
            //获取系统配置
            SystemConfig systemConfig = systemConfigDao.getSystemConfig();
            //System.out.println("获取的系统配置："+systemConfig);
            //获取被锁定时间
            Integer lockedTime = Integer.parseInt(systemConfig.getLockedTime());
            //允许登录失败的次数
            Integer loginFailedNum = Integer.parseInt(systemConfig.getLoginFailedNum());

            if(user.getLock()==CommonValue.USER_LOCK){
                //只有账号被锁定了，被锁定时间lockedDateTime才一定不为空
                String lockedDateTime = user.getLockedDateTime();
                DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
                LocalDateTime lastLockedDateTime = LocalDateTime.parse(lockedDateTime, fmt);
                LocalDateTime now = LocalDateTime.now();
                if(now.isAfter(lastLockedDateTime.plusMinutes(lockedTime)) ){
                    //账号已锁定并且未达到解锁要求，进行解锁
                    //修改数据库里的锁定标志
                    userDao.unlockSecUserById(user.getId());
                    //修改当前代码里面对象的锁定标志，减少一次读取数据库操作
                    user.setLock(0);
                    //锁定时间到，账户又可以尝试一定的次数
                    ServletUtil.updateFailedNum(username,0);
                }else{
                    //账号仍处于锁定状态,登录失败
                    if (!flag){
                        //鉴权时账号属于锁定
                        return JsonUtil.failedJson(CommonValue.USER_LOCK.toString());
                    }else{
                        return JsonUtil.failedJson(CommonValue.JSON_LOCK_ACCOUNT_lOGIN_FAILED);
                    }

                }
            }

            //判断ip
            String ipAddress = user.getIpAddress();
            if(!StringUtil.isEmptyString(ipAddress)){
                //ip不为空，设置了ip地址访问控制
                if(!ipAddress.equals(ServletUtil.getClientIp(request))){
                    //如果登录的ip地址，和数据库存储的ip地址不同，登录失败
                    LogUtil.produceWarningLogs(username,
                            CommonValue.WARNING_TYPE_0,
                            CommonValue.WARNING_LEVEL_0,
                            CommonValue.LOGIN_MODULE,
                            ServletUtil.getClientIp(request),
                            CommonValue.WARNING_TYPE_0+":用户名为"+username+"的IP地址异常，尝试登录IP为"+ServletUtil.getClientIp(request));
                    return JsonUtil.failedJson(CommonValue.JSON_ILLEGAL_IP_LOGIN);
                }
            }


            password = EncryptUtil.md5Encrypt(
                    password+(username+"wsn405").substring(0,7)
            );
            if(user!=null&&password.equals(user.getPassword())){
                //密码匹配了,账号的连续登录失败次数归0
                ServletUtil.updateFailedNum(username,0);

                //判断访问时间
                LocalTime nowTime = LocalTime.now();
                DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
                //默认全天可以访问
                LocalTime startTime =  LocalTime.parse(CommonValue.ACCESS_TIME_00_00, timeFormatter);
                LocalTime endTime =LocalTime.parse(CommonValue.ACCESS_TIME_23_59, timeFormatter);
                if(CommonValue.ACCESS_TIME_1.equals(user.getAccessTime())){
                    //8:30-17:00
                    startTime = LocalTime.parse(CommonValue.ACCESS_TIME_8_30, timeFormatter);
                    endTime = LocalTime.parse(CommonValue.ACCESS_TIME_17_00, timeFormatter);
                }else if(CommonValue.ACCESS_TIME_2.equals(user.getAccessTime())){
                    //8:30-11:30
                    startTime = LocalTime.parse(CommonValue.ACCESS_TIME_8_30, timeFormatter);
                    endTime = LocalTime.parse(CommonValue.ACCESS_TIME_11_30, timeFormatter);
                }else if(CommonValue.ACCESS_TIME_3.equals(user.getAccessTime())){
                    //13:30-17:00
                    startTime = LocalTime.parse(CommonValue.ACCESS_TIME_13_30, timeFormatter);
                    endTime = LocalTime.parse(CommonValue.ACCESS_TIME_17_00, timeFormatter);
                }

                if(nowTime.isBefore(startTime) || nowTime.isAfter(endTime)){
                    LogUtil.produceWarningLogs(username,
                            CommonValue.WARNING_TYPE_0,
                            CommonValue.WARNING_LEVEL_0,
                            CommonValue.LOGIN_MODULE,
                            ServletUtil.getClientIp(request),
                            CommonValue.WARNING_TYPE_0+":用户名为"+username+"在非访问时段尝试访问");
                    return JsonUtil.failedJson(CommonValue.JSON_LOGIN_TIME_ERROR);
                }

                if(flag){
                    //登录的时候
                    LogUtil.produceLogs(username,CommonValue.LOGIN_TYPE,CommonValue.LOGIN_LOGINFO,CommonValue.LOG_TYPE_BUS,CommonValue.SUCCESS);
                }else{
                    //鉴权的时候
                    LogUtil.produceLogs(username,CommonValue.AUTH_TYPE,CommonValue.AUTH_LOGINFO,CommonValue.LOG_TYPE_SYS,CommonValue.SUCCESS);
                }

                UserView userView = new UserView();
                userView.setUsername(user.getUsername());
                userView.setRole(user.getRole());
                userView.setCreateTime(user.getCreateTime());
                JSONObject jsonObject = JSONObject.fromObject(userView);
                //修改用户最近的登录时间
                userDao.setLastLoginTime(user.getId());

                //判断是否需要挤掉别人，控制同一用户只能一个客户端登录
                if(!isLogined)
                {
                    return JsonUtil.successJson(CommonValue.JSON_LOGIN_SUCCESS,jsonObject,null);
                }else
                    return JsonUtil.successJson(CommonValue.JSON_LOGIN_SUCCESS_ISLOGINED,jsonObject,null);
            }else {
                //登录失败
                if(user!=null){
                    //账号有效，即只是密码口令输入错误
                    //当前用户登录失败的次数
                    Integer num =  ServletUtil.getFailedNum(username);
                    num++;
                    //更新账号的失败次数
                    ServletUtil.updateFailedNum(username,num);
                    if(num>=loginFailedNum){
                        //如果用户账号未锁定或者超过锁定时间
                        //失败次数大于系统允许的次数，锁定用户
                        userDao.lockSecUserById(user.getId());
                        LogUtil.produceWarningLogs(username,
                                    CommonValue.WARNING_TYPE_0,
                                    CommonValue.WARNING_LEVEL_0,
                                    CommonValue.LOGIN_MODULE,
                                    ServletUtil.getClientIp(request),
                                    "用户名为:"+username+"连续登录失败次数超过限制,账号已锁定");
                        if (!flag){
                            //在鉴权的时候，如果输入密码次数过多，锁定了，页面会返回登陆界面
                            StorageUtil.getInstance().removeUser(username);//用户下线
                            return JsonUtil.failedJson(CommonValue.USER_LOCK.toString());
                        }else{
                            //登录界面的时候
                            return JsonUtil.failedJson(CommonValue.JSON_LOCK_ACCOUNT_lOGIN_FAILED);
                        }
                    }else{
                        //密码输入错误的次数没有到锁定账号的失败次数阈值
                        //普通警告日志;输错密码
                        LogUtil.produceWarningLogs(username,
                                    CommonValue.WARNING_TYPE_0,
                                    CommonValue.WARNING_LEVEL_1,
                                    CommonValue.LOGIN_MODULE,
                                    ServletUtil.getClientIp(request),
                                    "用户名为:"+username+"登录失败,累积登录失败:"+num+"次");
                    }
                }
                LogUtil.produceLogs(username,CommonValue.LOGIN_TYPE,
                        CommonValue.LOGIN_LOGINFO,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);

                if (!flag){
                    //在鉴权的时候，输错密码
                    return JsonUtil.failedJson(CommonValue.USER_UNLOCK.toString());
                }else{
                    //登录界面的时候
                    return JsonUtil.failedJson(CommonValue.JSON_lOGIN_FAILED);
                }
            }
        }else {
            //登录失败
            LogUtil.produceLogs(username,CommonValue.LOGIN_TYPE,CommonValue.LOGIN_LOGINFO,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    /**
     * 业务层，添加用户
     * @param username 表单提供用户名
     * @param role 角色
     * @return 注册成功与否的状态,并返回注册用户的信息（JSONObject）
     */
    public String dealUserCreate(String username,String role,String myUsername) throws UnsupportedEncodingException {

        if(username!=null&&!"".equals(username)&&role!=null&&!"".equals(role)&&myUsername!=null&&!"".equals(myUsername)){
            username = Regex.checkReg(username);
            role = Regex.checkReg(role);
            role = "auditor".equals(role)?"auditor":"operator";
            myUsername = Regex.checkReg(myUsername);
            User user = userDao.getUserByName(username);
            if(user!=null){
                LogUtil.produceLogs(myUsername,CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:"+role,
                        CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                return JsonUtil.failedJson(CommonValue.JSON_USERNAME_EXIST);
            }else {
                user = new User();
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                user.setCreateTime(sdf.format(date));
                user.setUsername(username);
                user.setPassword(CommonValue.DEFAULT_PASSWORD);
                user.setPassword(EncryptUtil.md5Encrypt(EncryptUtil.md5Encrypt(CommonValue.DEFAULT_PASSWORD+"scuwsn")+(username+"wsn405").substring(0,7)));
                user.setRole(role);
                boolean result = userDao.saveUser(user);
                if(result){
                    LogUtil.produceLogs(myUsername,CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:"+role,CommonValue.LOG_TYPE_BUS,CommonValue.SUCCESS);
                    return JsonUtil.successJson(CommonValue.JSON_CREATE_USER_SUCCESS, null,null);
                }else {
                    LogUtil.produceLogs(myUsername,CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:"+role,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                    return JsonUtil.failedJson(CommonValue.JSON_INSERT_FAILED);
                }
            }
        }else {
            LogUtil.produceLogs(myUsername,CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:"+role,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    public String dealAdminCreate(String username) throws UnsupportedEncodingException {

        if(username!=null&&!"".equals(username)){
            username = Regex.checkReg(username);
            User user = userDao.getUserByName(username);
            if(user!=null){
                return JsonUtil.failedJson(CommonValue.JSON_USERNAME_EXIST);
            }else {
                user = new User();
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
                user.setCreateTime(sdf.format(date));
                user.setUsername(username);
                user.setPassword(CommonValue.DEFAULT_PASSWORD);
                //user.setPassword(EncryptUtil.md5Encrypt(EncryptUtil.md5Encrypt(CommonValue.DEFAULT_PASSWORD+"scuwsn")+(username+"wsn405").substring(0,7)));
                user.setRole("admin");
                boolean result = userDao.saveUser(user);
                if(result){
                    LogUtil.produceLogs("*",CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:admin",CommonValue.LOG_TYPE_BUS,CommonValue.SUCCESS);
                    return JsonUtil.successJson(CommonValue.JSON_CREATE_USER_SUCCESS, null,null);
                }else {
                    LogUtil.produceLogs("*",CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:admin",CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                    return JsonUtil.failedJson(CommonValue.JSON_INSERT_FAILED);
                }
            }
        }else {
            LogUtil.produceLogs("*",CommonValue.CREATE_TYPE,CommonValue.CREATE_USER_LOGINFO+":"+username+",角色为:admin",CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    /**
     * 修改用户密码
     * @param username
     * @param formerPassword
     * @param newPassword
     * @param myUsername
     * @return
     */
    public String dealUserUpdate(String username,String formerPassword,String newPassword,String myUsername) throws Exception {
        //解密
//        formerPassword=Aes.aesDecrypt(formerPassword);
//        newPassword=Aes.aesDecrypt(newPassword);

        formerPassword=new String(RSAUtils.decryptByPrivateKey(Base64Utils.decode(formerPassword), RsaObj.getInstance().getPrivateKey()));
        newPassword=new String(RSAUtils.decryptByPrivateKey(Base64Utils.decode(newPassword), RsaObj.getInstance().getPrivateKey()));

        if(username!=null&&!"".equals(username)&&formerPassword!=null&&!"".equals(formerPassword)&&newPassword!=null&&!"".equals(newPassword)&&myUsername!=null&&!"".equals(myUsername)){
            username = Regex.checkReg(username);
            formerPassword = Regex.checkReg(formerPassword);
            newPassword = Regex.checkReg(newPassword);
            myUsername = Regex.checkReg(myUsername);
            //旧的信息
            User user = userDao.getUserByName(username);
            System.out.println("old:"+formerPassword);
            if(user!=null){
                //判断原密码正确
                if(formerPassword!=null&&EncryptUtil.md5Encrypt(formerPassword+(username+"wsn405").substring(0,7)).equals(user.getPassword())){
                    if(newPassword!=null&&!newPassword.isEmpty()){
                        newPassword = EncryptUtil.md5Encrypt(newPassword+(username+"wsn405").substring(0,7));
                        user.setPassword(newPassword);
                        boolean result = userDao.updateUser(username,user);
                        if(result){
                            LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.SUCCESS);
                            return JsonUtil.successJson(CommonValue.JSON_UPDATE_SUCCESS,null,null);
                        }else {
                            LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                            return JsonUtil.failedJson(CommonValue.JSON_UPDATE_FAILED);
                        }
                    }else {
                        LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                        return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
                    }
                }else {
                    LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                    return JsonUtil.failedJson(CommonValue.JSON_PASSWORD_FAILED);
                }

            }else {
                LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                return JsonUtil.failedJson(CommonValue.JSON_USERNAME_NOTEXIST);
            }
        }else {
            LogUtil.produceLogs(myUsername,CommonValue.UPDATE_TYPE,CommonValue.UPDATE_PWD,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    /**
     * 处理单个用户信息查询
     * @param username
     * @return
     */
    public String dealOneUserFind(String username){
        //按username查询
        if(username!=null&&!username.isEmpty()){
            User user = userDao.getUserByName(username);
            UserView userView = new UserView();
            userView.setUsername(user.getUsername());
            userView.setRole(user.getRole());
            userView.setCreateTime(user.getCreateTime());
            JSONObject jsonObject = JSONObject.fromObject(userView);
            return JsonUtil.successJson(CommonValue.JSON_QUERY_SUCCESS,jsonObject,null);
        }else {
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    /**
     * 条件查询多个用户
     * @param role
     * @param pageNum
     * @param pageSize
     * @return
     */
    public String dealUsersFindByRole(String role,String pageNum,String pageSize){

        //按角色查询
        List<User> list = userDao.listUsersByRole(role,pageNum,pageSize);
        List<UserView> userViewList = new ArrayList<>();
        for(User user : list){
            UserView userView = new UserView();
            userView.setUsername(user.getUsername());
            userView.setRole(user.getRole());
            userView.setCreateTime(user.getCreateTime());
            userViewList.add(userView);
        }
        JSONArray jsonArray = JSONArray.fromObject(userViewList);
        return JsonUtil.successJson(CommonValue.JSON_QUERY_SUCCESS, null, jsonArray);
    }

    /**
     * 查询所有用户
     * @param pageNum
     * @param pageSize
     * @return
     */
    public String dealAllUsersFind(String pageNum,String pageSize){
        List<User> allList = userDao.listAllUsers(pageNum,pageSize);
        List<UserView> userViewList = new ArrayList<>();
        for(User user : allList){
            UserView userView = new UserView();
            userView.setUsername(user.getUsername());
            userView.setRole(user.getRole());
            userView.setCreateTime(user.getCreateTime());
            userViewList.add(userView);
        }
        JSONArray jsonArray = JSONArray.fromObject(userViewList);
        return JsonUtil.successJson(CommonValue.JSON_QUERY_SUCCESS,null,jsonArray);
    }


    /**
     * 删除用户
     * @param username
     * @return
     */
    public String dealUserDelete(String username,String myUsername){
        if(username!=null&&!"".equals(username)){
            boolean result = userDao.deleteUser(username);
            if(result){
                LogUtil.produceLogs(myUsername,CommonValue.DELETE_TYPE,CommonValue.DELETE_USER_LOGINFO+":"+username,CommonValue.LOG_TYPE_BUS,CommonValue.SUCCESS);
                return JsonUtil.successJson(CommonValue.JSON_DELETE_SUCCESS, null,null);
            }else {
                LogUtil.produceLogs(myUsername,CommonValue.DELETE_TYPE,CommonValue.DELETE_USER_LOGINFO+":"+username,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
                return JsonUtil.failedJson(CommonValue.JSON_DELETE_FAILED);
            }
        }else {
            LogUtil.produceLogs(myUsername,CommonValue.DELETE_TYPE,CommonValue.DELETE_USER_LOGINFO+":"+username,CommonValue.LOG_TYPE_BUS,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

    public String dealFirstCheck(String username) throws UnsupportedEncodingException {
        if(username!=null&&!"".equals(username)){
            User user = userDao.getUserByName(username);
            String psw = user.getPassword();
            String encrypPsw = EncryptUtil.md5Encrypt(EncryptUtil.md5Encrypt("Wsn"+user.getIdCard().substring(
                    user.getIdCard().length()-6,
                    user.getIdCard().length())
                    +"scuwsn")+(user.getUsername()+"wsn405").substring(0,7));
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("permissionState",user.getPermission());
            if(psw.equals(encrypPsw)){
               // LogUtil.produceLogs(username,CommonValue.SELECTED_TYPE,CommonValue.JSON_FIRST_LOGIN+":"+username,CommonValue.SUCCESS);
                return JsonUtil.successJson(CommonValue.JSON_FIRST_LOGIN,jsonObject,null);
            }else {
                return JsonUtil.successJson(CommonValue.JSON_NOTFIRST_LOGIN,jsonObject,null);
            }
        }else{
            //LogUtil.produceLogs(username,CommonValue.SELECTED_TYPE,CommonValue.CHECK_FIRST+":"+username,CommonValue.FAILED);
            return JsonUtil.failedJson(CommonValue.JSON_INPUT_ERROR);
        }
    }

}
